package com.cskaoyan.javse.oop3._0abstract._0introduction;

/**
 * @description: 抽象类的引入
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

import javafx.animation.Animation;

/**
 * 思考
 *
 * Animal类的继承体系，有什么问题？
 * - 从代码角度上，有没有冗余代码？
 *      单纯从方法的角度考虑,Animal类当中的shout方法没有被调用,
 *      该方法单纯就是让子类继承并重写的,它实际上没有被调用的需求
 *      从理想的角度上来说,它的方法体是可以去掉的,仅保留一个声明让子类去重写就可以了
 *
 * - 从设计角度上，在这个案例中，会存在一个“动物”对象吗？
 *      不会,只会创建具体的动物对象,比如猫对象,狗对象.Animal这个类就不是为了创建对象而生的,而是为了被继承
 *      并且在这个案例中,动物实际上是一个抽象的概念,抽象的概念也不应该去描述它的行为(它的方法没有必要/也实现不了)
 *
 *  综上,我们提出两个改进的方向:
 *       1.Animal类就是为了继承的,不需要创建对象,于是干脆不要创建对象了
 *       2.Animal类当中的shout方法不需要方法体,不要描述一个抽象概念的叫声
 *
 * 于是就立刻去掉shout方法的方法体,并且加上分号,编译报错: Missing method body, or declare abstract
 * 普通的方法都是有方法体,如果想要方法没有方法体,需要声明为抽象
 * 如何声明一个抽象方法?
 * [访问权限修饰符] abstract 返回值类型 方法名(形参列表);
 * 需要注意语法中的分号,不要忘记了
 *
 * 直接在一个普通类中定义抽象方法,会编译报错:
 *      1.Abstract method in non-abstract class 抽象方法必须在抽象类中
 *      2.Class 'Animal' must either be declared abstract or implement abstract method 'shout()' in 'Animal'
 *          普通类中没有抽象方法,普通类中的方法都必须有方法体,都必须实现它,只有抽象类中才有抽象方法
 *
 * 怎么定义抽象类?
 * [访问权限修饰符] abstract class 类名{
 *     //类体
 * }
 *
 * 将抽象方法定义在抽象类中,程序就不会编译报错了,并且抽象类也是一个类,它仍然可以作为父类被子类继承
 * 如果一个普通类继承了抽象类,就必须实现抽象类中所有抽象方法
 *
 * 抽象类是不能创建对象的,它仍然可以用父类引用指向子类对象,它仍然可以发生多态现象
 *
 * 以上,使用抽象类改进案例就成功了!
 *
 */
public class Demo {
    public static void main(String[] args) {
        //'Animal' is abstract; cannot be instantiated
        //Animal animal = new Animal();

        Animal a;
        a = new Cat();
        a.shout();
        a = new Dog();
        a.shout();
    }
}
abstract class Animal {
    //'{' or ';' expected
    public abstract void shout();
}
class Cat extends Animal {
    @Override
    public void shout() {
        System.out.println("猫叫");
    }
}
class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("狗叫");
    }
}